
#include "../include/type.h"
#include"../include/client.h"


#define INTERVAL 5//采样周期
#define PACK_SIZE 200
#define DB_RECODE_MAX 30//默认数据库中存30条记录

void sig_quit(int signal);

void sig_timer(int signal);

void *thread_connect(void *args);


int stop_flag = DISABLE;//默认程序不退出,由信号向量异步设置
int sample_flag = DISABLE;//默认不采样,由定时中断异步设置
int connect_flag = UNLINK;//网络默认不连接
int have_flag = 1;//数据库中是否有数据，默认有一条

int sockfd = -1;

int main(int argc,char **argv)
{
    char                   		*serv_IP = NULL;
    int                    		serv_port = 0;
    char			            pack_buff[PACK_SIZE];//待发送数据包缓存区
    int				            pack_size = 0;//数据包大小
    int                    		rv = -1;
    pack_t                      sample_pack;//采样包

    sqlite3                     *db;
    static int                  recode_num = 0;//数据库中记录总数

    pthread_t                   thread_id;
    pthread_attr_t              pthread_attr;//线程属性
    pthread_args_t              *pthread_args ;//线程参数


    //初始化日志系统
    mylog_init();
    
    rv = argument_parse(argc,argv,&serv_IP,&serv_port);//参数解析
    if(rv < 0)
    {
        return 0;//退出程序
    }

    write_log_info("Parse server IP is %s\n",serv_IP);
    write_log_info("Parse server port is %d\n",serv_port);


    //ctrl+c退出程序
    if(signal(SIGQUIT,sig_quit) < 0)
    {
        write_log_error("signal SIGKILL failed:%s\n",strerror(errno));
        return 0;

    }

    //安装定时采样信号
    if(signal(SIGALRM,sig_timer) < 0)
    {
        write_log_error("signal SIGALRM faild:%s\n",strerror(errno));
        return 0;
    }

    //初始化数据库
    if(datbas_open(&db) < 0)
    {
        return 0;//退出程序
    }


    //初始化线程
    rv = pthread_init(&pthread_attr);
    if(rv < 0)
    {
        pthread_attr_destroy(&pthread_attr);
        return 0;
    }
     pthread_args = (pthread_args_t *)malloc(sizeof(pthread_args_t));
     pthread_args->serv_IP = serv_IP;
     pthread_args->serv_port = serv_port;

    //创建线程连接网络
    thread_start(&thread_id, thread_connect,  pthread_args);

    alarm(INTERVAL);//定时采样

    printf("Client starts to running...\n");
    recode_num = get_recode_count(db);//查看数据库中的记录总数
    printf("There are %d pieces of data in the current database\n",recode_num);

    //程序开始工作
    while(stop_flag == DISABLE)
    {
        memset(&sample_pack,0,sizeof(sample_pack));//清空采样数据缓存区

        //若网络已连接,且数据库中存在历史数据,且采样时间未到,则从数据库中取数据并发送
        if(connect_flag == LINK && recode_num && sample_flag == DISABLE)
        {
            //若数据库中有数据且采样时间不到，则上传数据库中的数据
            rv = get_recode(db,&sample_pack);//从数据库中取一条记录
            if(rv < 0)
            {
                goto Cleanup;//退出程序
            }
            sample_pack.s_pack.flag = 0;//设置历史数据不存入数据库
        }

        //若采样时间到,则开始采样新数据
        if(sample_flag == ENABLE)
        {
            printf("It's time to sample. Start sampling!\n");
            // DS_get_tem(&sample_pack);
            strcpy(sample_pack.s_pack.temp,"15063");   
            strcpy(sample_pack.s_pack.sn,"RPI00001");

            rv = get_date_time(&sample_pack);//获取日期和时间
            if(rv < 0)
            {
                sample_flag = DISABLE;//重新等待采样
                printf("Don't get time , recover sample!\n");
                continue;
            }
            printf("OK! Sampling completed!\n");
            sample_pack.s_pack.flag = NEWDATA|SAVEDATA;//设置新数据和存入数据库
            sample_flag = DISABLE;//清除采样标志,重新等待采样
             
       }

        //数据打包、发送、存储
        if(!struct_is_empty(&sample_pack))
        {
            memset(pack_buff,0,sizeof(pack_buff));//清空数据包缓存区
            pack_size = tlv_pack(&sample_pack, pack_buff,sizeof(pack_buff));//tlv打包数据

            if(connect_flag == LINK)//网络连接正常
            {
                rv = send_pack_to_server(sockfd,pack_buff,pack_size+1,1,1);//发送数据包
                if(rv < 0)//出错,保存数据并退出程序
                {
                    stop_flag = ENABLE;//将数据存入数据库后退出程序
                }
                else if(rv == UNLINK)//网络断开,保存数据
                {
                    connect_flag = UNLINK;//设置网络无连接
                    close(sockfd);//关闭套接字
                }
                else//成功接收到数据,清除标志，重新采样
                {

                    //若成功发送历史数据,则删除数据库中的这条记录
                    if(!(sample_pack.s_pack.flag & NEWDATA))
                    {
                        rv = delete_recode(db,sample_pack.s_pack.id,0);//从数据库中删除指定的这一条记录
                        if(rv < 0)
                        {
                            goto Cleanup;
                        }
                        else
                        {
                            recode_num = recode_num - 1;//删除成功,记录数减1
                        }
                    }
                    sample_pack.s_pack.flag = 0;//清除标志
                }
            }

            //存入数据库
            if(sample_pack.s_pack.flag & SAVEDATA)
            {
                //检查数据库表的记录数是否达到上限
                recode_num = get_recode_count(db);
                if(recode_num >= DB_RECODE_MAX)
                {
                    printf("Records in the database reach the upper limit and are deleted!\n");
                    rv = delete_recode(db,10,1);//从数据库中删除前10条数据
                    if(rv < 0)
                    {
                        goto Cleanup;
                    }
                    else
                    {
                        recode_num = recode_num - 10;//记录数减少10
                    }
                }
                //存入数据操作
                rv =  datbas_insert(db,sample_pack.s_pack.date,sample_pack.s_pack.time,sample_pack.s_pack.sn,sample_pack.s_pack.temp);
                if(rv < 0)
                {
                    goto Cleanup;
                }
                else
                {
                    recode_num = recode_num + 1;//插入数据之后,记录数+1
                    sample_pack.s_pack.flag = 0;//存入成功,清除标志
                }
            }
        }
    }

Cleanup:
    datbas_close(db);//关闭数据库
    close(sockfd);//关闭文件描述符
    return 0;

}


void sig_quit(int signo)
{
    stop_flag = ENABLE;
    printf("ctrl+c Program exited!\n");
}

void sig_timer(int signo)
{
    sample_flag = ENABLE;
    alarm(INTERVAL);
}


void *thread_connect(void *args)
{
    pthread_args_t      *pthread_args = (pthread_args_t *)args;

    while(1)
    {
        if(connect_flag == UNLINK)
        {
            sockfd = socket_connect(pthread_args->serv_IP,pthread_args->serv_port);//连接服务器
            if(sockfd > 0)//连接成功
            {

                connect_flag = LINK;//标记网络已连接
            }

            else
            {
                sleep(5);//连接失败延时5后重连
            }
        }
    }
}


